Skip to main content

03 软件双缓冲

1 采样不能等串口​

FFT主课先停下来处理一帧,是为了便于验证。真正连续采集时,ADC还在不断产生新数据,CPU必须在数据被覆盖前处理完。

设8 kHz采样,一个数组512个半字,分成前后各256点。DMA写后半区时,CPU处理前半区;DMA绕回前半区时,CPU处理后半区。每次只有32 ms可用。

F103C8T6的DMA通道没有两个内存地址寄存器组成的硬件双缓冲,本方案是循环DMA加半传输/传输完成中断。

2 CubeMX配置与工作顺序​

沿用FFT实验的TIM3触发、ADC1单通道与DMA连接,但本页预算采用8 kHz:TIM3时钟72 MHz、PSC=71、ARR=124,区别于原工程5 kHz的ARR=199。把DMA模式改成Circular循环模式,数组长度改为512;两端仍为Half Word,内存自增,开启DMA1 Channel1中断。

前256点写满 → 半传输回调 → CPU处理前半区 / DMA写后半区
后256点写满 → 完成回调 → CPU处理后半区 / DMA写前半区

回调只登记“哪一半完成”,不要在其中运行FFT、滤波或串口打印。

3 数据比标志位更重要​

最容易犯的错误是只用一个 ready = 1。CPU来不及处理时,第二次事件把第一次覆盖了,程序看起来还在运行,但数据已经不连续。

可靠的实现至少要满足:

  1. 用递增的完成序号记录每次半缓冲完成,主循环比较序号差,检测错过的块。
  2. 在下一次DMA进入该半区之前完成读取或复制,关CPU中断也不会停止DMA。
  3. 复制完再次检查完成序号和DMA当前位置;若时间边界被跨过,丢弃这一帧并记录错误。

这里的关键不是“越多缓冲越好”,若平均处理速度比数据到达速度慢,最终仍然会满。初学时先用单帧版测出耗时,再决定是否进入连续版。

4 把时间先算出来​

项目本课程例子
每半缓冲时间256 / 8000 = 32 ms
可用CPU周期72 MHz × 32 ms = 2304000 cycles
原始16位数据流8000 × 2 = 16000 byte/s
115200、8N1理论有效字节率115200 / 10 = 11520 byte/s

所以115200波特率连完整的二进制原始流都传不完,更不要说每个点转成十进制文本。可只发主峰和幅度,或降低采样率、抽取显示数据、提高实际可用串口带宽。抽取作为信号降采样时,先做抗混叠低通;单纯少显示一些点不能视作严格的信号重采样。

可以在处理函数前后翻转一个空闲GPIO,用示波器测量高电平宽度,记录最坏耗时。

6 工程验收​

连续运行并记录最大处理耗时、ADC极值和UART拥塞情况。只有采样稳定、没有覆盖、输出带宽充足,频谱和滤波结果才有意义。